/**
 * This class manages all character objects (player, monsters, bullets), level, scores,...
 *
 *
 */
function Map(viewWidth, viewHeight) {

	this.width = COLS * CELL_SIZE;
	this.height = ROWS * CELL_SIZE;
	this.viewWidth = viewWidth;
	this.viewHeight = viewHeight;

	this.level = _level || 0;
	var data;
	var enemiesQueue;

	this.scores = 0;

	var startingScores = 0;

	var BG_RATIO = _images.background.height / this.height;
	var BG_VIEW_WIDTH = viewWidth * BG_RATIO;
	var BG_VIEW_HEIGHT = viewHeight * BG_RATIO;


	var pipes = [];
	pipes.push({
		x: 600,
		y: this.height - CELL_SIZE - 100,
		width: 50,
		height: 100
	});
	pipes.push({
		x: 1200,
		y: this.height - CELL_SIZE - 100,
		width: 50,
		height: 100
	});

	var itemsSprite = new StaticSprite({
		image: _images.object,
		frameWidth: 57,
		frameHeight: 57
	});
	// add flower sprite
	itemsSprite.addSprite({
		name: "flower",
		frameIndex: 18,
		marginTop: 6,
		marginBottom: 12,
		marginLeft: 4,
		marginRight: 8

	});
	// add donut sprite
	itemsSprite.addSprite({
		name: "donut",
		frameIndex: 88,
		marginTop: 4,
		marginBottom: 4,
		marginLeft: 4,
		marginRight: 4

	});
	// add wood sprite
	itemsSprite.addSprite({
		name: "wood",
		frameIndex: 84,
		marginTop: 0,
		marginBottom: 0,
		marginLeft: 0,
		marginRight: 0
	});

	itemsSprite.addSprite({
		name: "wall",
		frameIndex: 89,
		marginTop: 0,
		marginBottom: 0,
		marginLeft: 0,
		marginRight: 0
	});
	itemsSprite.addSprite({
		name: "strawberry",
		frameIndex: 85,
		marginTop: 9,
		marginBottom: 8,
		marginLeft: 11,
		marginRight: 11

	});
    itemsSprite.addSprite({
		name: "pumpkin",
		frameIndex: 86,
		marginTop: 2,
		marginBottom: 2,
		marginLeft: 2,
		marginRight: 2

	});
	itemsSprite.addSprite({
		name: "yellow_bird_bullet",
		frameIndex: 90,
		marginTop: 9,
		marginBottom: 9,
		marginLeft: 10,
		marginRight: 10
	});
	itemsSprite.addSprite({
		name: "black_bird_bullet",
		frameIndex: 91,
		marginTop: 5,
		marginBottom: 5,
		marginLeft: 8,
		marginRight: 8
	});

	if (this.width < this.viewWidth || this.height < this.viewHeight) {
		alert("Error: The viewport is larger than the map.");
		return;
	}
	this.deadzone = {
		left: this.viewWidth / 4,
		top: this.viewHeight / 4,
		right: this.viewWidth / 4 * 3,
		bottom: this.viewHeight / 4 * 3,
	};

	this.deadzone.width = this.deadzone.right - this.deadzone.left;
	this.deadzone.height = this.deadzone.bottom - this.deadzone.top;

	// buffer
	var buffer = document.createElement("canvas");
	buffer.width = this.width;
	buffer.height = this.height;
	var context = buffer.getContext("2d");

	// return false if player has reached the last level; otherwise, return true
	this.nextLevel = function() {
		startingScores = this.scores; // store the scores from previous level
		this.level++;
		if (this.level == MAPS.length)
			this.level = 0;

		return this.level != 0;

	};
	// new game
	this.reset = function() {

		this.scores = (this.level == 0) ? 0 : startingScores;

		var castlePos = {
			x: this.width - 300,
			y: 600 - _images.castle.height - CELL_SIZE
		};
		this.endPoint = {
			x: castlePos.x + _images.castle.width / 2,
			y: castlePos.y + _images.castle.height
		};

        
		this.bullets = [];
		this.monsters = [];
		this.plants = [];
        
		this.offsetX = 0;
		this.offsetY = 0;
        this.monsters.push(new Monster(this, this.endPoint.x, this.endPoint.y, true));
        
		data = MAPS[this.level].data.slice(0); // clone
		enemiesQueue = MAPS[this.level].enemies.slice(0);
        
		// create the map buffer
		context.clearRect(0, 0, buffer.width, buffer.height);

		for (var i = 0; i < COLS; i++) {
			for (var j = 0; j < ROWS; j++) {
				var val = data[i + j * COLS];
                // draw object
				if (val != 0) {
					if (val == DONUT) {
						itemsSprite.sprites.donut.draw(context, i * CELL_SIZE, j * CELL_SIZE, CELL_SIZE, CELL_SIZE);
					} else if(val == PUMPKIN){
					   data[i + j * COLS] = PUMPKIN;
                       itemsSprite.sprites.pumpkin.draw(context, i * CELL_SIZE, j * CELL_SIZE, CELL_SIZE, CELL_SIZE);
					} else if (val == ROCK) {
						data[i + j * COLS] = YELLOW_BIRD_WOOD;
						itemsSprite.sprites.wall.draw(context, i * CELL_SIZE, j * CELL_SIZE, CELL_SIZE, CELL_SIZE);
					} else if (val == STRAWBERRY) {
						itemsSprite.sprites.strawberry.draw(context, i * CELL_SIZE, j * CELL_SIZE, CELL_SIZE, CELL_SIZE);
					} else if (val == PIPE && data[(i - 1) + j * COLS] != PIPE) {

						if (data[i + (j - 1) * COLS] != PIPE) {
							context.drawImage(_images.pipe_head, i * CELL_SIZE - 5, j * CELL_SIZE, CELL_SIZE * 2 + 10, CELL_SIZE);
							// add a piranha plant to this pipe
							var p = new PiranhaPlant(this, i * CELL_SIZE + HALF_SIZE, j * CELL_SIZE);
							p.top -= p.height;
							this.plants.push(p);
						} else
							context.drawImage(_images.pipe_body, i * CELL_SIZE, j * CELL_SIZE, CELL_SIZE * 2, CELL_SIZE);
					} else if (val == YELLOW_BIRD_BULLET) {
						itemsSprite.sprites.yellow_bird_bullet.draw(context, i * CELL_SIZE, j * CELL_SIZE, CELL_SIZE, CELL_SIZE);
					} else if (val == BLACK_BIRD_BULLET) {
						itemsSprite.sprites.black_bird_bullet.draw(context, i * CELL_SIZE, j * CELL_SIZE, CELL_SIZE, CELL_SIZE);
					} else {
						if (val == LAND)
							itemsSprite.sprites.wall.draw(context, i * CELL_SIZE, j * CELL_SIZE, CELL_SIZE, CELL_SIZE);
						else if (val == WOOD || val == ROCK_WOOD)
							itemsSprite.sprites.wood.draw(context, i * CELL_SIZE, j * CELL_SIZE, CELL_SIZE, CELL_SIZE);

					}
				}
			}
		}
		context.drawImage(_images.castle, castlePos.x, castlePos.y);
	};


	function clearCell(left, top, col, row) {
		data[col + row * COLS] = 0;
		context.save();
		context.globalCompositeOperation = "destination-out";
		context.fillStyle = "rgba(0,0,0,1)";
		context.fillRect(left, top, CELL_SIZE, CELL_SIZE);
		context.restore();
	}

	this.update = function() {
		var i = 0;
		var length = this.bullets.length;
		// update bullets
		while (i < length) {
			if (this.bullets[i].isDead) {
				this.bullets.splice(i, 1);
				length--;
			} else {
				this.bullets[i].update();
				i++;
			}
		}
        
		i = 0;
		var length = this.monsters.length;
        //console.log(this.monsters);
		while (i < length) {
			if (this.monsters[i].isDead) {
				this.monsters.splice(i, 1);
				length--;
			} else {
				this.monsters[i].update();
				i++;         
            }
        }
        
		i = 0;
		var length = this.plants.length;
		while (i < length) {
			if (this.plants[i].isDead) {
				this.plants.splice(i, 1);
				length--;
			} else {
				this.plants[i].update();
				i++;
			}
		}
        
        // automatic add monster
        if(this.monsters[0] != undefined) {
            if(this.monsters[0].isKing) {
        		var time = (new Date()).getTime();
        		var d = time - this.monsters[i].lastPause;
                //console.log("King");
        		if (d > 5000) {
        			this.monsters[0].lastPause = time;
                
                    this.monsters.push(new Monster(this, this.monsters[0].left, this.monsters[0].top, false));
                    //this.monsters[i].draw(ctx);
        		}
            }
        }
            
		// check and add new monster from the enemiesQueue
		var col = Math.floor((this.offsetX + this.viewWidth) / CELL_SIZE);
		if (enemiesQueue.length > 0 && enemiesQueue[0].col <= col) {
			// remove the first enemy from queue
			var e = enemiesQueue.shift();
			// and add it to the monsters collection
			this.monsters.push(new Monster(this, e.col * CELL_SIZE, e.row * CELL_SIZE, false));
		}

	};
	this.draw = function(ctx, obj) {

		var dx = obj.left - this.offsetX;
		var dy = obj.top - this.offsetY;

		if (dx < this.deadzone.left)
			this.offsetX = obj.left - this.deadzone.left;
		else if (dx + obj.width > this.deadzone.right)
			this.offsetX = obj.right - this.deadzone.right;

		if (dy < this.deadzone.top)
			this.offsetY = obj.top - this.deadzone.top;
		else if (dy + obj.height > this.deadzone.bottom)
			this.offsetY = obj.bottom - this.deadzone.bottom;

		if (this.offsetX < 0)
			this.offsetX = 0;
		else if (this.offsetX + this.viewWidth > buffer.width)
			this.offsetX = buffer.width - this.viewWidth;

		if (this.offsetY < 0)
			this.offsetY = 0;
		else if (this.offsetY + this.viewHeight > buffer.height)
			this.offsetY = buffer.height - this.viewHeight;


		// draw the background

		var left = (this.offsetX * BG_RATIO) % _images.background.width;
		var top = this.offsetY * BG_RATIO;

		if (left + BG_VIEW_WIDTH > _images.background.width) {
			var bW = _images.background.width - left;
			var vW = bW / BG_RATIO;
			ctx.drawImage(_images.background, left, top, bW, BG_VIEW_HEIGHT,
				0, 0, vW, viewHeight);

			bW = BG_VIEW_WIDTH - bW;
			ctx.drawImage(_images.background, 0, top, bW, BG_VIEW_HEIGHT,
				vW - 1, 0, bW / BG_RATIO, viewHeight);
		} else {
            ctx.drawImage(_images.background, left, top, BG_VIEW_WIDTH, BG_VIEW_HEIGHT, 0, 0, viewWidth, viewHeight);
        }

		ctx.drawImage(buffer, this.offsetX, this.offsetY, this.viewWidth, this.viewHeight,
			0, 0, this.viewWidth, this.viewHeight);

		for (x in this.bullets) {
			this.bullets[x].draw(ctx);
		}
		for (x in this.monsters) {
			this.monsters[x].draw(ctx);
		}
		for (x in this.plants)
			this.plants[x].draw(ctx);
        
        // draw scores
        ctx.font = "20px disney";
		ctx.fillStyle = "black";
		ctx.fillText("SCORES: " + this.scores, 20, 30);
        // draw level
        ctx.fillText("LEVEL: " + (_level + 1), 600, 30);
        // draw life
        ctx.drawImage(_images.object, 4, 120, 51, 48, 700, 10, 25, 24);
        ctx.fillText("x " + _live, 740, 30);

	};

	this.colllide = function(x, y, canDestroy, canEat) {
		var b = this.contain(x, y);
        //console.log("b: " + b);

		if (b) {
			if (b.type == DONUT || b.type == STRAWBERRY || b.type == PUMPKIN) {
				if (canEat) {
				    if(!_isMute) {
				        soundManager.play("eat_fruit");
				    }
					this.scores += 10;
					clearCell(b.left, b.top, b.col, b.row);
				}
				return;
			} else if (b.type == BLACK_BIRD_BULLET) {
                // eat black bird bullet
				if (canEat) {
				    if(!_isMute) {
				        soundManager.play("eat_fruit");
				    }
                    this.scores += 20;
					clearCell(b.left, b.top, b.col, b.row);
					return true;
				}
				return;
			} else if (b.type == YELLOW_BIRD_BULLET) {
                // eat yellow bullet
				if (canEat) {
				    if(!_isMute) {
				        soundManager.play("eat_fruit");
				    }
                    this.scores += 15;
                    _speed = MAX_SPEED;
					clearCell(b.left, b.top, b.col, b.row);
					return;// true;
				}
			}

			if (canDestroy && b.type != ROCK) {
				// destroy wood
				if (b.type == WOOD) {
				    if(!_isMute){
				        soundManager.play("destroy_rock");
				    }
					clearCell(b.left, b.top, b.col, b.row);
				} else if (b.type == ROCK_WOOD) // add new mushroom
				{
					data[b.col + b.row * COLS] = ROCK;
					itemsSprite.sprites.wall.draw(context, b.left, b.top, CELL_SIZE, CELL_SIZE);			
				}
			}
			return b;
		}
		return false;
	};
	this.contain = function(x, y) {
		var col = Math.floor(x / CELL_SIZE);
		var row = Math.floor(y / CELL_SIZE);
		var val = data[col + row * COLS];
		if (val > 0) {
			var b = {
				left: col * CELL_SIZE,
				top: row * CELL_SIZE,
				col: col,
				row: row,
				type: val,
			};
			b.right = b.left + CELL_SIZE;
			b.bottom = b.top + CELL_SIZE;

			return b;
		}
		return false;
	};

}